package com.yyy.reflect;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Project ：learn_spring
 * @File ：TestCar.java
 * @IDE ：IntelliJ IDEA
 * @Author ：自由如风间
 * @Date ：2025/3/31 15:45
 * @Description ：For study.
 */

public class TestCar {

    // 1.获取Class对象多种方式
    @Test
    public void test01() {
        // 1 类名.class
        Class clazz1 = Car.class;

        // 2 对象.getClass()
        Class clazz2 = new Car().getClass();

        // 3 Class.forName("全路径")
        try {
            Class clazz3 = Class.forName("com.yyy.reflect.Car");

            try {
                Car car = (Car) clazz3.getDeclaredConstructor().newInstance();
                System.out.println(car);
            } catch (InstantiationException |
                     NoSuchMethodException |
                     IllegalAccessException |
                     InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    // 2.获取构造方法
    @Test
    public void test02() {
        Class<Car> clazz = Car.class;

        // 获取所有构造，但是是public的
        // Constructor<?>[] constructors = clazz.getConstructors();

        // 也可以获取private的
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> c : constructors) {
            System.out.println("原始输出:" + c);
            System.out.println("其他输出:" + c.getName() + " "
                    + c.getParameterTypes() + " "
                    + c.getParameterCount());
            // System.out.println();
        }

        // 指定有参构造创建对象
        // 1.适用于构造public
        /*
        try {
            Constructor c1 = clazz.getConstructor(String.class, Integer.class, String.class);
            try {
                Car car = (Car) c1.newInstance("别摸我", 20, "红粉相间");
                System.out.println(car);
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        */

        // 2.构造private
        try {
            Constructor c1 = clazz.getDeclaredConstructor(String.class, Integer.class, String.class);
            // 设置私有属性可以访问
            c1.setAccessible(true);
            try {
                Car car = (Car) c1.newInstance("蓝波鸡你", 30, "红粉相间");
                System.out.println(car);
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    // 3.获取属性
    @Test
    public void test03() {
        Class<Car> clazz = Car.class;

        // 获取所有public属性
        Field[] fields = clazz.getFields();
        System.out.println("公开属性：");
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println();

        // 获取所有属性（包括私有）
        Field[] declaredFields = clazz.getDeclaredFields();
        try {
            Car car = clazz.getDeclaredConstructor().newInstance();
            System.out.println("所有属性：");
            for (Field df : declaredFields) {
                if (df.getName().equals("brand")) {
                    // 设置允许访问
                    df.setAccessible(true);
                    df.set(car, "法拉利");
                }
                System.out.println(df.getAnnotatedType());
            }
            System.out.println(car);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    // 4.获取方法
    @Test
    public void test04() {
        Car car = new Car("奔驰", 10, "BLACK");
        Class<? extends Car> clazz = car.getClass();
        // 获取public方法
        Method[] methods = clazz.getMethods();
        System.out.println( "Public Part:");
        for (Method m : methods) {
            System.out.println(m.getName());
            // 执行toString方法
            if (m.getName().equals("toString")) {
                try {
                    String ivk = (String) m.invoke(car);
                    System.out.println(ivk);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        // private方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        System.out.println("\nPrivate Part:");
        for (Method dm : declaredMethods) {
            // 如果调用私有方法，要先设置setAccessible为true
            System.out.println(dm.getName());
        }
    }
}
